#region Imported Namespaces


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

using WtfManager.Framework;


#endregion


namespace WtfManager.UIManager
{
  ///<summary>
  /// Loads and manages UI assemblies.
  ///</summary>
  public class UIService: Service
  {
    #region Fields


    private readonly ObservableCollection<UIAssemblyInfo> _assemblies = new ObservableCollection<UIAssemblyInfo>();


    #endregion


    #region Properties/Indexers


    ///<summary>
    /// Gets a list of loaded UI assemblies.
    ///</summary>
    public ReadOnlyObservableCollection<UIAssemblyInfo> Assemblies
    {
      get
      {
        return new ReadOnlyObservableCollection<UIAssemblyInfo>(_assemblies);
      }
    }


    /// <summary>
    /// Gets a description of a service.
    /// </summary>
    public override string Description
    {
      get
      {
        return "Loads and manages UI assemblies.";
      }
    }


    /// <summary>
    /// Gets a name of a service.
    /// </summary>
    public override string Name
    {
      get
      {
        return "UI Service";
      }
    }


    #endregion


    #region Methods


    protected override void OnStateChnaged()
    {
    }


    protected override FrameworkComponentState OnLoad()
    {
      string modulesDirectory = WtfFramework.Instance.ModulesDirectory;

      string[] assemblies = Directory.GetFiles(modulesDirectory, "*.dll");

      foreach (string assemblyName in assemblies)
      {
        try
        {
          Assembly assembly = Assembly.LoadFrom(assemblyName);
          object[] attributes = assembly.GetCustomAttributes(typeof(UIAssemblyAttribute), false);

          if (attributes != null && attributes.Length != 0)
          {
            var assemblyInfo = new UIAssemblyInfo(assembly);
            _assemblies.Add(assemblyInfo);
          }
        }
        catch
        {
          continue;
        }
      }

      return FrameworkComponentState.Loaded;
    }


    protected override void OnUnload()
    {
      _assemblies.Clear();
    }


    private static void ShowWindow(UIControlInfo windowType)
    {
      if (!windowType.IsOfType<Window>())
      {
        return;
      }

      var instance = (Window)windowType.CreateInstance();
      instance.Show();
    }


    ///<summary>
    /// Determines whether a specified object is a content container.
    ///</summary>
    ///<param name="control">An object to check.</param>
    public bool IsContentContainer(object control)
    {
      if (control is ContentControl)
      {
        Type type = control.GetType();
        foreach (UIAssemblyInfo assemblyInfo in _assemblies)
        {
          foreach (UIControlInfo controlInfo in assemblyInfo.ContentContainerTypes)
          {
            if (controlInfo.ControlType == type)
            {
              return true;
            }
          }
        }
      }

      return false;
    }


    public UIControlInfo GetContentContainer(ContentControl control)
    {
      Type type = control.GetType();
      string fullTypeName = type.FullName;

      return GetContentContainer(fullTypeName);
    }


    public UIControlInfo GetContentContainer(string fullTypeName)
    {
      foreach (UIAssemblyInfo assemblyInfo in _assemblies)
      {
        foreach (UIControlInfo controlInfo in assemblyInfo.ContentContainerTypes)
        {
          if (controlInfo.ControlType.FullName == fullTypeName)
          {
            return controlInfo;
          }
        }
      }

      return null;
    }


    ///<summary>
    /// Gets a <see cref="UIControlInfo">content container</see> for a specified content Type.
    ///</summary>
    ///<param name="contentType">The Type of content to get container for.</param>
    ///<returns>null, if no corresponding container control was found.</returns>
    public UIControlInfo GetContentContainer(Type contentType)
    {
      foreach (UIAssemblyInfo assemblyInfo in _assemblies)
      {
        foreach (UIControlInfo containerType in assemblyInfo.ContentContainerTypes)
        {
          if (containerType.IsValidContentType(contentType))
          {
            return containerType;
          }
        }
      }

      return null;
    }


    public UIControlInfo GetPanel(Type panelType)
    {
      return GetPanel(panelType.FullName);
    }


    public UIControlInfo GetPanel(string fullTypeName)
    {
      foreach (UIAssemblyInfo assemblyInfo in _assemblies)
      {
        foreach (UIControlInfo panel in assemblyInfo.PanelControls)
        {
          if (panel.ControlType.FullName == fullTypeName)
          {
            return panel;
          }
        }
      }

      return null;
    }


    public List<UIControlInfo> GetPanels()
    {
      var panels = new List<UIControlInfo>();

      foreach (UIAssemblyInfo assemblyInfo in _assemblies)
      {
        foreach (UIControlInfo panel in assemblyInfo.PanelControls)
        {
          panels.Add(panel);
        }
      }

      return panels;
    }


    protected override FrameworkComponentState OnInitialize()
    {
      foreach (UIAssemblyInfo assemblyInfo in _assemblies)
      {
        foreach (UIControlInfo controlInfo in assemblyInfo.StartupWindowTypes)
        {
          try
          {
            ShowWindow(controlInfo);
          }
          catch
          {
            // TODO <RNovitsky, 29.04.2009>: Log this
            continue;
          }
        }
      }

      return FrameworkComponentState.Initialized;
    }


    public Window GetCurrentWindow()
    {
      return GetCurrentWindow(Keyboard.FocusedElement as DependencyObject);
    }


    public Window GetCurrentWindow(DependencyObject dependencyObject)
    {
      while(dependencyObject != null)
      {
        if(dependencyObject is Window)
        {
          return (Window)dependencyObject;
        }

        dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
      }

      return null;
    }


    #endregion
  }
}